﻿//#include <windows.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <map>
#include <time.h>

#include "orange.h"
#include "fruit.h"
#include "gate.h"


static const int orderCheck = 31415926; // 这个必须预知
static int orderRegiste = 314159;
static int orderToast = 7;
static int orderLogon = 8;
static const int orderDisconect = 2;  // 这个也是(...)
static int orderTime = 10;
static int orderClose = 99999;

static CONNID connectionId = 0;
static std::string version = "v20200401";
static std::string logName = "1970-0000.log";

static std::set<std::string> ip_blacklist;
static std::map<CONNID, std::string> connections; // 有效连接,有效版本,可注册
static std::set<int> airingInstans = { 11 };
static std::set<int> listOrders = { 210 };
static std::set<int> gnoreOrders = { 
	orderRegiste, 2, 3, 6, 17, 18,
	25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
	41, 43,
	93, 94, 
	105,
};
static std::set<CONNID> airingConnections; // 有效登录
static std::list<sAir> airings;
static const unsigned char* preData = nullptr;
static int preDataLength = 0;
HANDLE handle = nullptr;

ccc_new_lock;
EnHandleResult __stdcall OnAccept(HP_Server pSender, CONNID dwConnID, SOCKET soClient)
{
	ccc_en_lock;
	static unsigned short port;
	auto strip = getIp(pSender, dwConnID, port);
	SetConsoleTextAttribute(handle, 0x6); // 黄
	std::cout << "(" << dwConnID << "):" << strip << ":" << port;
	if (std::find(ip_blacklist.cbegin(), ip_blacklist.cend(), strip) == ip_blacklist.cend())
	{
		std::cout << std::endl;
	}
	else
	{
		SetConsoleTextAttribute(handle, 0x4); // 红
		std::cout << "(黑名单)" << std::endl;
	}
	SetConsoleTextAttribute(handle, 0x7);
	ccc_un_lock;
	return HR_OK;
}
EnHandleResult __stdcall OnReceive(HP_Server pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
	ccc_en_lock;
	unsigned char* arr = (unsigned char*)pData;
	if (connectionId == 0)
	{
		if (iLength == 0x100 + 24 && checkMatrix(orderCheck, arr, iLength))
		{
			orderRegiste = *(int*)(arr + 0x100 + 4);
			orderToast = *(int*)(arr + 0x100 + 8);
			orderLogon = *(int*)(arr + 0x100 + 12);
			orderTime = *(int*)(arr + 0x100 + 16);
			orderClose = *(int*)(arr + 0x100 + 20);

			memset(arr, 0, c21);
			*(unsigned long*)arr = dwConnID;
			*(int*)(arr + 4) = orderCheck;
			*(arr + c21 - 1) = -1;
			::HP_Server_Send(pSender, dwConnID, arr, c21);
			connectionId = dwConnID;
			connections.erase(dwConnID);
		}
		else
		{
			eatClient(pSender, dwConnID, orderDisconect, "连接失败");
		}
		ccc_un_lock;
		return HR_OK;
	}
	int order;
	char type;
	if (dwConnID == connectionId)
	{
		// cid + (order + type)
		fromServer(arr, dwConnID, order, type);
		//std::cout << dwConnID << " " << order << " " << (int)type << ":" << std::string((char*)arr, iLength) << std::endl;
		if ((order != orderLogon && order != orderTime) || type != typeNil)
		{
			iLength -= 4;
			arr = easyApple(arr + 4, iLength);
			if (arr == nullptr)
			{
				ccc_un_lock;
				return HR_OK;
			}
		}
		const auto& it2 = listOrders.find(order);
		if (it2 != listOrders.end())
		{
			pushAiring(airings, dwConnID, arr, iLength);
			ccc_un_lock;
			return HR_OK;
		}
		if (order == orderLogon)
		{
			if (type == typeNil)
			{
				airingConnections.insert(dwConnID);
				std::stringstream str;
				str << "在线人数:" << airingConnections.size();
				SetConsoleTitle(str.str().c_str());

				if (preData != nullptr)
				{
					::HP_Server_Send(pSender, dwConnID, preData, preDataLength);
				}
			}
			else
			{
				if (preData != nullptr)
				{
					delete[] preData;
				}
				preData = arr;
				preDataLength = iLength;
			}
			ccc_un_lock;
			return HR_OK;
		}
		if (order == orderTime)
		{
			char ptr[32];
			memset(ptr, 0, sizeof(ptr));
			*(int*)ptr = order;
			*(ptr + 4) = 1;
			std::stringstream sstr;
			sstr << time(nullptr);
			iLength = sstr.str().length();
			memcpy(ptr + 5, sstr.str().c_str(), iLength);
			iLength += 5;
			arr = easyApple((unsigned char*)ptr, iLength);
			if (arr != nullptr)
			{
				::HP_Server_Send(pSender, dwConnID, arr, iLength);
				delete[] arr;
			}
			ccc_un_lock;
			return HR_OK;
		}
		if (dwConnID == 0)
		{
			const auto& it = airingInstans.find(order);
			if (it == airingInstans.end())
			{
				pushAiring(airings, airingConnections, arr, iLength);
			}
			else
			{
				for (const auto& cid : airingConnections)
				{
					::HP_Server_Send(pSender, cid, arr, iLength);
				}
				delete[] arr;
			}
			ccc_un_lock;
			return HR_OK;
		}
		::HP_Server_Send(pSender, dwConnID, arr, iLength);
		delete[] arr;
		ccc_un_lock;
		return HR_OK;
	}
	// 解压
	arr = eatOrange(arr, iLength);
	auto strip = getIp(pSender, dwConnID);
	if (arr == nullptr)
	{
		time_t tick;
		tm tm;
		tick = time(nullptr);
		tm = *localtime(&tick);
		char s64[64];
		strftime(s64, sizeof(s64), "%m%d-%H:%M:%S", &tm);
		std::cout << s64 << ' ' << strip << "\tinvalid" << std::endl;

		ccc_un_lock;
		return HR_OK;
	}
#define ccc_delete_arrunc delete[] arr; ccc_un_lock
	unsigned long t;
	int orderInner, parameter, roleId;
	fromClient(arr, t, order, orderInner, parameter, roleId, type);

//	writeLog(logName, dwConnID, order, strip, arr + c21, iLength - c21);
	if(gnoreOrders.find(order) != gnoreOrders.cend())
	{
		time_t tick;
		tm tm;
		tick = time(nullptr);
		tm = *localtime(&tick);
		char s64[64];
		strftime(s64, sizeof(s64), "%m%d-%H:%M:%S", &tm);

		unsigned char c;
		c = arr[iLength];
		arr[iLength] = 0;
		std::cout << s64 << ' ' << strip << '\t' << order << '\t' << (arr + c21) << std::endl;
		arr[iLength] = c;
	}

	if (order == orderCheck)
	{
		if (!checkVersion(version, orderInner, parameter, type, arr + c21, iLength - c21))
		{
			eatClient(pSender, dwConnID, orderDisconect, "版本过旧");
			ccc_delete_arrunc;
			return HR_OK;
		}
		connections.emplace(dwConnID, strip);
		*(unsigned long*)arr = dwConnID;
		eatChecked(pSender, connectionId, arr, iLength, strip);
		ccc_delete_arrunc;
		return HR_OK;
	}
	const auto& it = connections.find(dwConnID);
	if (it == connections.cend())
	{
		eatillegal(pSender, dwConnID, orderDisconect);
		ccc_delete_arrunc;
		return HR_OK;
	}
	if (order == orderRegiste)
	{
		if (type != typeString)
		{
			eatillegal(pSender, dwConnID, orderDisconect);
			ccc_delete_arrunc;
			return HR_OK;
		}
		if (!checkRegiste(arr + c21, orderInner))
		{
			eatClient(pSender, dwConnID, orderDisconect, "不能特殊字符");
			ccc_delete_arrunc;
			return HR_OK;
		}
		*(unsigned long*)arr = dwConnID;
		*(arr + c21 - 1) = (unsigned char)strlen(strip);
		eatRegiste(pSender, connectionId, arr, iLength, strip);
		ccc_delete_arrunc;
		return HR_OK;
	}
	//	std::cout << dwConnID << " " << order << " " << orderInner << " " << parameter << " " << roleId << " " << (int)type << ":" << std::string((char*)arr, iLength) << std::endl;
	if (airingConnections.find(dwConnID) != airingConnections.cend() && std::abs((int)((unsigned long)time(nullptr) - t)) > 3)
	{
		eatClient(pSender, dwConnID, orderDisconect, "连接超时");
		ccc_delete_arrunc;
		return HR_OK;
	}
	// 转发
	*(unsigned long*)arr = dwConnID;
	::HP_Server_Send(pSender, connectionId, arr, iLength);
	ccc_delete_arrunc;
	return HR_OK;
}


EnHandleResult __stdcall OnClose(HP_Server pSender, CONNID dwConnID, En_HP_SocketOperation enOperation, int iErrorCode)
{
	HP_Server_Disconnect(pSender, dwConnID, TRUE);
	SetConsoleTextAttribute(handle, 0x2); // 绿
	const auto& it = connections.find(dwConnID);
	if (it != connections.end())
	{
		std::cout << "(" << it->first << "):" << it->second << "(退出)" << std::endl;
		connections.erase(it);
	}
	else
	{
		std::cout << "(" << dwConnID << "):退出" << std::endl;
	}
	SetConsoleTextAttribute(handle, 0x7);
	airingConnections.erase(dwConnID);
	std::stringstream str;
	str << "在线人数:" << airingConnections.size();
	SetConsoleTitle(str.str().c_str());
	if (dwConnID == connectionId)
	{
		connectionId = 0;
	}
	else if (connectionId != 0)
	{
		static unsigned char arr[c21];
		memset(arr, 0, c21);
		*(unsigned long*)arr = dwConnID;
		*(int*)(arr + 4) = orderClose;
		*(arr + c21 - 1) = typeNil;
		::HP_Server_Send(pSender, connectionId, arr, c21);
	}
	return HR_OK;
}
// EnHandleResult __stdcall OnShutdown(HP_Server pSender)
// {
// 	return HR_OK;
// }


int main(int argc, char* argv[])
{
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	srand(time(nullptr));
	printf("made in china by狼\n");
	std::string ip = "127.0.0.1";
	int port = 0xFEDC;
	if (argc > 1)
	{
		version = argv[1];
		if (argc > 2)
		{
			std::string temp = argv[2];
			if (temp != "-")
			{
				ip = temp;
			}
			if (argc > 3)
			{
				temp = argv[3];
				if (temp != "-")
				{
					port = std::atoi(temp.c_str());
				}
			}
		}
	}


	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE; //移除快速编辑模式
	mode &= ~ENABLE_INSERT_MODE; //移除插入模式
	mode &= ~ENABLE_MOUSE_INPUT;
	SetConsoleMode(hStdin, mode);

	blackList(ip_blacklist);

	auto pListener = ::Create_HP_TcpPackServerListener();
	auto pServer = ::Create_HP_TcpPackServer(pListener);
//	::HP_Set_FN_Server_OnPrepareListen(pListener, OnPrepareListen);
	::HP_Set_FN_Server_OnAccept(pListener, OnAccept);
//	::HP_Set_FN_Server_OnSend(pListener, OnSend);
	::HP_Set_FN_Server_OnReceive(pListener, OnReceive);
	::HP_Set_FN_Server_OnClose(pListener, OnClose);
//	::HP_Set_FN_Server_OnShutdown(pListener, OnShutdown);

	::HP_TcpPackServer_SetMaxPackSize(pServer, cFFF);
	::HP_TcpPackServer_SetPackHeaderFlag(pServer, 0x163);

	if (::HP_Server_Start(pServer, ip.c_str(), port) == TRUE)
	{
		std::cout << ip << ":" << port << std::endl;
	}

	ccc_init_lock;

	setLogName(logName);

	for (;;)
	{
		popAiring(pServer, airings);
		Sleep(1);
	}	

	::Destroy_HP_TcpPackServer(pServer);
	::Destroy_HP_TcpServerListener(pListener);
	ccc_del_lock;
	return 0;
}

